/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.meducated.sim.model;

import java.util.Comparator;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;

/**
 * A DependencyGraph is a connected graph of dependent objects (node) of type T
 * and uni-directional dependencies (edges) between those objects.
 *
 *
 * @author Carina
 */
public class PropertyDependencyGraph implements Comparator<Property> {

    /**
     *
     */
    private Map<Property, SortedSet<Property>> dependencies;

    /**
     *
     */
    public PropertyDependencyGraph() {
        this.dependencies = new ConcurrentHashMap<Property, SortedSet<Property>>();
    }

    /**
     *
     * @param from
     * @param to
     * @return
     */
    public boolean add(Property from, Property to) {
        if (!dependencies.containsKey(from)) {
            this.dependencies.put(from, new TreeSet<Property>(this));
        }
        SortedSet<Property> dependents;
        dependents = this.dependencies.get(from);
        return dependents.add(to);
    }

    /**
     *
     * @param from
     * @param to
     * @return
     */
    public boolean remove(Property from, Property to) {
        if (!dependencies.containsKey(from)) {
            return false;
        } else {
            Set<Property> dependents;
            if ((dependents = dependencies.get(from)) == null) {
                return false;
            }
            return dependents.remove(to);
        }
    }

    /**
     *
     * @param object
     * @return
     */
    private void remove(Property object) {
        dependencies.remove(object);
        for (Set<Property> s : dependencies.values()) {
            s.remove(object);
        }
    }

    /**
     * Returns the objects which are dependent on the specified object.
     *
     * @param dependee
     * @return
     */
    public SortedSet<Property> getDependents(Property t) {
        return this.dependencies.get(t);
    }

    public SortedSet<Property> getAllDependents(Property t) {
        Set<Property> deps;
        if ((deps = dependencies.get(t)) != null) {
            SortedSet<Property> all = new TreeSet<Property>(this);
            all.addAll(deps);
            for (Property p : deps) {
                if (!p.equals(t)) {
                    SortedSet<Property> deps2;
                    if ((deps2 = getAllDependents(p)) != null) {
                        all.addAll(deps2);
                    }
                }
            }
            return all;
        } else {
            return null;
        }
    }

    /**
     *
     * @param dependent
     * @param dependee
     * @return
     */
    public boolean isDependent(Property from, Property to) {
        if (!dependencies.containsKey(from)) {
            return false;
        } else {
            if(this.dependencies.get(from).contains(to)) {
                return true;
            }
            else {
                for(Property p : this.dependencies.get(from)) {
                    if(isDependent(p, to)) {
                        return true;
                    }
                }
                return false;
            }
        }
    }

    /**
     * 
     * @param t
     * @param t1
     * @return 
     */
    @Override
    public int compare(Property t, Property t1) {
        if (isDependent(t, t1)) {
            return -1;
        } else if (isDependent(t1, t)) {
            return +1;
        } else if(t.equals(t1)) {
            return 0;
        } else {
            return t.hashCode()
                    - t1.hashCode();
        }
    }
}

